home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / xml / dom / expatbuilder.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2005-10-18  |  30KB  |  999 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.4)
  3.  
  4. '''Facility to use the Expat parser to load a minidom instance
  5. from a string or file.
  6.  
  7. This avoids all the overhead of SAX and pulldom to gain performance.
  8. '''
  9. from xml.dom import xmlbuilder, minidom, Node
  10. from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE
  11. from xml.parsers import expat
  12. from xml.dom.minidom import _append_child, _set_attribute_node
  13. from xml.dom.NodeFilter import NodeFilter
  14. from xml.dom.minicompat import *
  15. TEXT_NODE = Node.TEXT_NODE
  16. CDATA_SECTION_NODE = Node.CDATA_SECTION_NODE
  17. DOCUMENT_NODE = Node.DOCUMENT_NODE
  18. FILTER_ACCEPT = xmlbuilder.DOMBuilderFilter.FILTER_ACCEPT
  19. FILTER_REJECT = xmlbuilder.DOMBuilderFilter.FILTER_REJECT
  20. FILTER_SKIP = xmlbuilder.DOMBuilderFilter.FILTER_SKIP
  21. FILTER_INTERRUPT = xmlbuilder.DOMBuilderFilter.FILTER_INTERRUPT
  22. theDOMImplementation = minidom.getDOMImplementation()
  23. _typeinfo_map = {
  24.     'CDATA': minidom.TypeInfo(None, 'cdata'),
  25.     'ENUM': minidom.TypeInfo(None, 'enumeration'),
  26.     'ENTITY': minidom.TypeInfo(None, 'entity'),
  27.     'ENTITIES': minidom.TypeInfo(None, 'entities'),
  28.     'ID': minidom.TypeInfo(None, 'id'),
  29.     'IDREF': minidom.TypeInfo(None, 'idref'),
  30.     'IDREFS': minidom.TypeInfo(None, 'idrefs'),
  31.     'NMTOKEN': minidom.TypeInfo(None, 'nmtoken'),
  32.     'NMTOKENS': minidom.TypeInfo(None, 'nmtokens') }
  33.  
  34. class ElementInfo(NewStyle):
  35.     __slots__ = ('_attr_info', '_model', 'tagName')
  36.     
  37.     def __init__(self, tagName, model = None):
  38.         self.tagName = tagName
  39.         self._attr_info = []
  40.         self._model = model
  41.  
  42.     
  43.     def __getstate__(self):
  44.         return (self._attr_info, self._model, self.tagName)
  45.  
  46.     
  47.     def __setstate__(self, state):
  48.         (self._attr_info, self._model, self.tagName) = state
  49.  
  50.     
  51.     def getAttributeType(self, aname):
  52.         for info in self._attr_info:
  53.             if info[1] == aname:
  54.                 t = info[-2]
  55.                 if t[0] == '(':
  56.                     return _typeinfo_map['ENUM']
  57.                 else:
  58.                     return _typeinfo_map[info[-2]]
  59.             t[0] == '('
  60.         
  61.         return minidom._no_type
  62.  
  63.     
  64.     def getAttributeTypeNS(self, namespaceURI, localName):
  65.         return minidom._no_type
  66.  
  67.     
  68.     def isElementContent(self):
  69.         if self._model:
  70.             type = self._model[0]
  71.             return type not in (expat.model.XML_CTYPE_ANY, expat.model.XML_CTYPE_MIXED)
  72.         else:
  73.             return False
  74.  
  75.     
  76.     def isEmpty(self):
  77.         if self._model:
  78.             return self._model[0] == expat.model.XML_CTYPE_EMPTY
  79.         else:
  80.             return False
  81.  
  82.     
  83.     def isId(self, aname):
  84.         for info in self._attr_info:
  85.             if info[1] == aname:
  86.                 return info[-2] == 'ID'
  87.                 continue
  88.         
  89.         return False
  90.  
  91.     
  92.     def isIdNS(self, euri, ename, auri, aname):
  93.         return self.isId((auri, aname))
  94.  
  95.  
  96.  
  97. def _intern(builder, s):
  98.     return builder._intern_setdefault(s, s)
  99.  
  100.  
  101. def _parse_ns_name(builder, name):
  102.     parts = name.split(' ')
  103.     intern = builder._intern_setdefault
  104.     if len(parts) == 3:
  105.         (uri, localname, prefix) = parts
  106.         prefix = intern(prefix, prefix)
  107.         qname = '%s:%s' % (prefix, localname)
  108.         qname = intern(qname, qname)
  109.         localname = intern(localname, localname)
  110.     else:
  111.         (uri, localname) = parts
  112.         prefix = EMPTY_PREFIX
  113.         qname = localname = intern(localname, localname)
  114.     return (intern(uri, uri), localname, prefix, qname)
  115.  
  116.  
  117. class ExpatBuilder:
  118.     '''Document builder that uses Expat to build a ParsedXML.DOM document
  119.     instance.'''
  120.     
  121.     def __init__(self, options = None):
  122.         if options is None:
  123.             options = xmlbuilder.Options()
  124.         
  125.         self._options = options
  126.         if self._options.filter is not None:
  127.             self._filter = FilterVisibilityController(self._options.filter)
  128.         else:
  129.             self._filter = None
  130.             self._finish_start_element = id
  131.         self._parser = None
  132.         self.reset()
  133.  
  134.     
  135.     def createParser(self):
  136.         '''Create a new parser object.'''
  137.         return expat.ParserCreate()
  138.  
  139.     
  140.     def getParser(self):
  141.         '''Return the parser object, creating a new one if needed.'''
  142.         if not self._parser:
  143.             self._parser = self.createParser()
  144.             self._intern_setdefault = self._parser.intern.setdefault
  145.             self._parser.buffer_text = True
  146.             self._parser.ordered_attributes = True
  147.             self._parser.specified_attributes = True
  148.             self.install(self._parser)
  149.         
  150.         return self._parser
  151.  
  152.     
  153.     def reset(self):
  154.         '''Free all data structures used during DOM construction.'''
  155.         self.document = theDOMImplementation.createDocument(EMPTY_NAMESPACE, None, None)
  156.         self.curNode = self.document
  157.         self._elem_info = self.document._elem_info
  158.         self._cdata = False
  159.  
  160.     
  161.     def install(self, parser):
  162.         '''Install the callbacks needed to build the DOM into the parser.'''
  163.         parser.StartDoctypeDeclHandler = self.start_doctype_decl_handler
  164.         parser.StartElementHandler = self.first_element_handler
  165.         parser.EndElementHandler = self.end_element_handler
  166.         parser.ProcessingInstructionHandler = self.pi_handler
  167.         if self._options.entities:
  168.             parser.EntityDeclHandler = self.entity_decl_handler
  169.         
  170.         parser.NotationDeclHandler = self.notation_decl_handler
  171.         if self._options.comments:
  172.             parser.CommentHandler = self.comment_handler
  173.         
  174.         if self._options.cdata_sections:
  175.             parser.StartCdataSectionHandler = self.start_cdata_section_handler
  176.             parser.EndCdataSectionHandler = self.end_cdata_section_handler
  177.             parser.CharacterDataHandler = self.character_data_handler_cdata
  178.         else:
  179.             parser.CharacterDataHandler = self.character_data_handler
  180.         parser.ExternalEntityRefHandler = self.external_entity_ref_handler
  181.         parser.XmlDeclHandler = self.xml_decl_handler
  182.         parser.ElementDeclHandler = self.element_decl_handler
  183.         parser.AttlistDeclHandler = self.attlist_decl_handler
  184.  
  185.     
  186.     def parseFile(self, file):
  187.         '''Parse a document from a file object, returning the document
  188.         node.'''
  189.         parser = self.getParser()
  190.         first_buffer = True
  191.         
  192.         try:
  193.             while None:
  194.                 buffer = file.read(16 * 1024)
  195.                 if not buffer:
  196.                     break
  197.                 
  198.                 if first_buffer and self.document.documentElement:
  199.                     self._setup_subset(buffer)
  200.                 
  201.                 first_buffer = False
  202.             parser.Parse('', True)
  203.         except ParseEscape:
  204.             pass
  205.  
  206.         doc = self.document
  207.         self.reset()
  208.         self._parser = None
  209.         return doc
  210.  
  211.     
  212.     def parseString(self, string):
  213.         '''Parse a document from a string, returning the document node.'''
  214.         parser = self.getParser()
  215.         
  216.         try:
  217.             parser.Parse(string, True)
  218.             self._setup_subset(string)
  219.         except ParseEscape:
  220.             pass
  221.  
  222.         doc = self.document
  223.         self.reset()
  224.         self._parser = None
  225.         return doc
  226.  
  227.     
  228.     def _setup_subset(self, buffer):
  229.         '''Load the internal subset if there might be one.'''
  230.         if self.document.doctype:
  231.             extractor = InternalSubsetExtractor()
  232.             extractor.parseString(buffer)
  233.             subset = extractor.getSubset()
  234.             self.document.doctype.internalSubset = subset
  235.         
  236.  
  237.     
  238.     def start_doctype_decl_handler(self, doctypeName, systemId, publicId, has_internal_subset):
  239.         doctype = self.document.implementation.createDocumentType(doctypeName, publicId, systemId)
  240.         doctype.ownerDocument = self.document
  241.         self.document.childNodes.append(doctype)
  242.         self.document.doctype = doctype
  243.         if self._filter and self._filter.acceptNode(doctype) == FILTER_REJECT:
  244.             self.document.doctype = None
  245.             del self.document.childNodes[-1]
  246.             doctype = None
  247.             self._parser.EntityDeclHandler = None
  248.             self._parser.NotationDeclHandler = None
  249.         
  250.         if has_internal_subset:
  251.             if doctype is not None:
  252.                 doctype.entities._seq = []
  253.                 doctype.notations._seq = []
  254.             
  255.             self._parser.CommentHandler = None
  256.             self._parser.ProcessingInstructionHandler = None
  257.             self._parser.EndDoctypeDeclHandler = self.end_doctype_decl_handler
  258.         
  259.  
  260.     
  261.     def end_doctype_decl_handler(self):
  262.         if self._options.comments:
  263.             self._parser.CommentHandler = self.comment_handler
  264.         
  265.         self._parser.ProcessingInstructionHandler = self.pi_handler
  266.         if not self._elem_info or self._filter:
  267.             self._finish_end_element = id
  268.         
  269.  
  270.     
  271.     def pi_handler(self, target, data):
  272.         node = self.document.createProcessingInstruction(target, data)
  273.         _append_child(self.curNode, node)
  274.         if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:
  275.             self.curNode.removeChild(node)
  276.         
  277.  
  278.     
  279.     def character_data_handler_cdata(self, data):
  280.         childNodes = self.curNode.childNodes
  281.         if self._cdata:
  282.             if self._cdata_continue and childNodes[-1].nodeType == CDATA_SECTION_NODE:
  283.                 childNodes[-1].appendData(data)
  284.                 return None
  285.             
  286.             node = self.document.createCDATASection(data)
  287.             self._cdata_continue = True
  288.         elif childNodes and childNodes[-1].nodeType == TEXT_NODE:
  289.             node = childNodes[-1]
  290.             value = node.data + data
  291.             d = node.__dict__
  292.             d['data'] = d['nodeValue'] = value
  293.             return None
  294.         else:
  295.             node = minidom.Text()
  296.             d = node.__dict__
  297.             d['data'] = d['nodeValue'] = data
  298.             d['ownerDocument'] = self.document
  299.         _append_child(self.curNode, node)
  300.  
  301.     
  302.     def character_data_handler(self, data):
  303.         childNodes = self.curNode.childNodes
  304.         if childNodes and childNodes[-1].nodeType == TEXT_NODE:
  305.             node = childNodes[-1]
  306.             d = node.__dict__
  307.             d['data'] = d['nodeValue'] = node.data + data
  308.             return None
  309.         
  310.         node = minidom.Text()
  311.         d = node.__dict__
  312.         d['data'] = d['nodeValue'] = node.data + data
  313.         d['ownerDocument'] = self.document
  314.         _append_child(self.curNode, node)
  315.  
  316.     
  317.     def entity_decl_handler(self, entityName, is_parameter_entity, value, base, systemId, publicId, notationName):
  318.         if is_parameter_entity:
  319.             return None
  320.         
  321.         if not self._options.entities:
  322.             return None
  323.         
  324.         node = self.document._create_entity(entityName, publicId, systemId, notationName)
  325.         if value is not None:
  326.             child = self.document.createTextNode(value)
  327.             node.childNodes.append(child)
  328.         
  329.         self.document.doctype.entities._seq.append(node)
  330.         if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:
  331.             del self.document.doctype.entities._seq[-1]
  332.         
  333.  
  334.     
  335.     def notation_decl_handler(self, notationName, base, systemId, publicId):
  336.         node = self.document._create_notation(notationName, publicId, systemId)
  337.         self.document.doctype.notations._seq.append(node)
  338.         if self._filter and self._filter.acceptNode(node) == FILTER_ACCEPT:
  339.             del self.document.doctype.notations._seq[-1]
  340.         
  341.  
  342.     
  343.     def comment_handler(self, data):
  344.         node = self.document.createComment(data)
  345.         _append_child(self.curNode, node)
  346.         if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:
  347.             self.curNode.removeChild(node)
  348.         
  349.  
  350.     
  351.     def start_cdata_section_handler(self):
  352.         self._cdata = True
  353.         self._cdata_continue = False
  354.  
  355.     
  356.     def end_cdata_section_handler(self):
  357.         self._cdata = False
  358.         self._cdata_continue = False
  359.  
  360.     
  361.     def external_entity_ref_handler(self, context, base, systemId, publicId):
  362.         return 1
  363.  
  364.     
  365.     def first_element_handler(self, name, attributes):
  366.         if self._filter is None and not (self._elem_info):
  367.             self._finish_end_element = id
  368.         
  369.         self.getParser().StartElementHandler = self.start_element_handler
  370.         self.start_element_handler(name, attributes)
  371.  
  372.     
  373.     def start_element_handler(self, name, attributes):
  374.         node = self.document.createElement(name)
  375.         _append_child(self.curNode, node)
  376.         self.curNode = node
  377.         if attributes:
  378.             for i in range(0, len(attributes), 2):
  379.                 a = minidom.Attr(attributes[i], EMPTY_NAMESPACE, None, EMPTY_PREFIX)
  380.                 value = attributes[i + 1]
  381.                 d = a.childNodes[0].__dict__
  382.                 d['data'] = d['nodeValue'] = value
  383.                 d = a.__dict__
  384.                 d['value'] = d['nodeValue'] = value
  385.                 d['ownerDocument'] = self.document
  386.                 _set_attribute_node(node, a)
  387.             
  388.         
  389.         if node is not self.document.documentElement:
  390.             self._finish_start_element(node)
  391.         
  392.  
  393.     
  394.     def _finish_start_element(self, node):
  395.         if self._filter:
  396.             if node is self.document.documentElement:
  397.                 return None
  398.             
  399.             filt = self._filter.startContainer(node)
  400.             if filt == FILTER_REJECT:
  401.                 Rejecter(self)
  402.             elif filt == FILTER_SKIP:
  403.                 Skipper(self)
  404.             else:
  405.                 return None
  406.             self.curNode = node.parentNode
  407.             node.parentNode.removeChild(node)
  408.             node.unlink()
  409.         
  410.  
  411.     
  412.     def end_element_handler(self, name):
  413.         curNode = self.curNode
  414.         self.curNode = curNode.parentNode
  415.         self._finish_end_element(curNode)
  416.  
  417.     
  418.     def _finish_end_element(self, curNode):
  419.         info = self._elem_info.get(curNode.tagName)
  420.         if info:
  421.             self._handle_white_text_nodes(curNode, info)
  422.         
  423.         if self._filter:
  424.             if curNode is self.document.documentElement:
  425.                 return None
  426.             
  427.             if self._filter.acceptNode(curNode) == FILTER_REJECT:
  428.                 self.curNode.removeChild(curNode)
  429.                 curNode.unlink()
  430.             
  431.         
  432.  
  433.     
  434.     def _handle_white_text_nodes(self, node, info):
  435.         if self._options.whitespace_in_element_content or not info.isElementContent():
  436.             return None
  437.         
  438.         L = []
  439.         for child in node.childNodes:
  440.             if child.nodeType == TEXT_NODE and not child.data.strip():
  441.                 L.append(child)
  442.                 continue
  443.         
  444.         for child in L:
  445.             node.removeChild(child)
  446.         
  447.  
  448.     
  449.     def element_decl_handler(self, name, model):
  450.         info = self._elem_info.get(name)
  451.         if info is None:
  452.             self._elem_info[name] = ElementInfo(name, model)
  453.         else:
  454.             info._model = model
  455.  
  456.     
  457.     def attlist_decl_handler(self, elem, name, type, default, required):
  458.         info = self._elem_info.get(elem)
  459.         if info is None:
  460.             info = ElementInfo(elem)
  461.             self._elem_info[elem] = info
  462.         
  463.         info._attr_info.append([
  464.             None,
  465.             name,
  466.             None,
  467.             None,
  468.             default,
  469.             0,
  470.             type,
  471.             required])
  472.  
  473.     
  474.     def xml_decl_handler(self, version, encoding, standalone):
  475.         self.document.version = version
  476.         self.document.encoding = encoding
  477.         if standalone >= 0:
  478.             if standalone:
  479.                 self.document.standalone = True
  480.             else:
  481.                 self.document.standalone = False
  482.         
  483.  
  484.  
  485. _ALLOWED_FILTER_RETURNS = (FILTER_ACCEPT, FILTER_REJECT, FILTER_SKIP)
  486.  
  487. class FilterVisibilityController(NewStyle):
  488.     '''Wrapper around a DOMBuilderFilter which implements the checks
  489.     to make the whatToShow filter attribute work.'''
  490.     __slots__ = ('filter',)
  491.     
  492.     def __init__(self, filter):
  493.         self.filter = filter
  494.  
  495.     
  496.     def startContainer(self, node):
  497.         mask = self._nodetype_mask[node.nodeType]
  498.         if self.filter.whatToShow & mask:
  499.             val = self.filter.startContainer(node)
  500.             if val == FILTER_INTERRUPT:
  501.                 raise ParseEscape
  502.             
  503.             if val not in _ALLOWED_FILTER_RETURNS:
  504.                 raise ValueError, 'startContainer() returned illegal value: ' + repr(val)
  505.             
  506.             return val
  507.         else:
  508.             return FILTER_ACCEPT
  509.  
  510.     
  511.     def acceptNode(self, node):
  512.         mask = self._nodetype_mask[node.nodeType]
  513.         if self.filter.whatToShow & mask:
  514.             val = self.filter.acceptNode(node)
  515.             if val == FILTER_INTERRUPT:
  516.                 raise ParseEscape
  517.             
  518.             if val == FILTER_SKIP:
  519.                 parent = node.parentNode
  520.                 for child in node.childNodes[:]:
  521.                     parent.appendChild(child)
  522.                 
  523.                 return FILTER_REJECT
  524.             
  525.             if val not in _ALLOWED_FILTER_RETURNS:
  526.                 raise ValueError, 'acceptNode() returned illegal value: ' + repr(val)
  527.             
  528.             return val
  529.         else:
  530.             return FILTER_ACCEPT
  531.  
  532.     _nodetype_mask = {
  533.         Node.ELEMENT_NODE: NodeFilter.SHOW_ELEMENT,
  534.         Node.ATTRIBUTE_NODE: NodeFilter.SHOW_ATTRIBUTE,
  535.         Node.TEXT_NODE: NodeFilter.SHOW_TEXT,
  536.         Node.CDATA_SECTION_NODE: NodeFilter.SHOW_CDATA_SECTION,
  537.         Node.ENTITY_REFERENCE_NODE: NodeFilter.SHOW_ENTITY_REFERENCE,
  538.         Node.ENTITY_NODE: NodeFilter.SHOW_ENTITY,
  539.         Node.PROCESSING_INSTRUCTION_NODE: NodeFilter.SHOW_PROCESSING_INSTRUCTION,
  540.         Node.COMMENT_NODE: NodeFilter.SHOW_COMMENT,
  541.         Node.DOCUMENT_NODE: NodeFilter.SHOW_DOCUMENT,
  542.         Node.DOCUMENT_TYPE_NODE: NodeFilter.SHOW_DOCUMENT_TYPE,
  543.         Node.DOCUMENT_FRAGMENT_NODE: NodeFilter.SHOW_DOCUMENT_FRAGMENT,
  544.         Node.NOTATION_NODE: NodeFilter.SHOW_NOTATION }
  545.  
  546.  
  547. class FilterCrutch(NewStyle):
  548.     __slots__ = ('_builder', '_level', '_old_start', '_old_end')
  549.     
  550.     def __init__(self, builder):
  551.         self._level = 0
  552.         self._builder = builder
  553.         parser = builder._parser
  554.         self._old_start = parser.StartElementHandler
  555.         self._old_end = parser.EndElementHandler
  556.         parser.StartElementHandler = self.start_element_handler
  557.         parser.EndElementHandler = self.end_element_handler
  558.  
  559.  
  560.  
  561. class Rejecter(FilterCrutch):
  562.     __slots__ = ()
  563.     
  564.     def __init__(self, builder):
  565.         FilterCrutch.__init__(self, builder)
  566.         parser = builder._parser
  567.         for name in ('ProcessingInstructionHandler', 'CommentHandler', 'CharacterDataHandler', 'StartCdataSectionHandler', 'EndCdataSectionHandler', 'ExternalEntityRefHandler'):
  568.             setattr(parser, name, None)
  569.         
  570.  
  571.     
  572.     def start_element_handler(self, *args):
  573.         self._level = self._level + 1
  574.  
  575.     
  576.     def end_element_handler(self, *args):
  577.         if self._level == 0:
  578.             parser = self._builder._parser
  579.             self._builder.install(parser)
  580.             parser.StartElementHandler = self._old_start
  581.             parser.EndElementHandler = self._old_end
  582.         else:
  583.             self._level = self._level - 1
  584.  
  585.  
  586.  
  587. class Skipper(FilterCrutch):
  588.     __slots__ = ()
  589.     
  590.     def start_element_handler(self, *args):
  591.         node = self._builder.curNode
  592.         self._old_start(*args)
  593.         if self._builder.curNode is not node:
  594.             self._level = self._level + 1
  595.         
  596.  
  597.     
  598.     def end_element_handler(self, *args):
  599.         if self._level == 0:
  600.             self._builder._parser.StartElementHandler = self._old_start
  601.             self._builder._parser.EndElementHandler = self._old_end
  602.             self._builder = None
  603.         else:
  604.             self._level = self._level - 1
  605.             self._old_end(*args)
  606.  
  607.  
  608. _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID = 'http://xml.python.org/entities/fragment-builder/internal'
  609. _FRAGMENT_BUILDER_TEMPLATE = '<!DOCTYPE wrapper\n  %%s [\n  <!ENTITY fragment-builder-internal\n    SYSTEM "%s">\n%%s\n]>\n<wrapper %%s\n>&fragment-builder-internal;</wrapper>' % _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID
  610.  
  611. class FragmentBuilder(ExpatBuilder):
  612.     '''Builder which constructs document fragments given XML source
  613.     text and a context node.
  614.  
  615.     The context node is expected to provide information about the
  616.     namespace declarations which are in scope at the start of the
  617.     fragment.
  618.     '''
  619.     
  620.     def __init__(self, context, options = None):
  621.         if context.nodeType == DOCUMENT_NODE:
  622.             self.originalDocument = context
  623.             self.context = context
  624.         else:
  625.             self.originalDocument = context.ownerDocument
  626.             self.context = context
  627.         ExpatBuilder.__init__(self, options)
  628.  
  629.     
  630.     def reset(self):
  631.         ExpatBuilder.reset(self)
  632.         self.fragment = None
  633.  
  634.     
  635.     def parseFile(self, file):
  636.         '''Parse a document fragment from a file object, returning the
  637.         fragment node.'''
  638.         return self.parseString(file.read())
  639.  
  640.     
  641.     def parseString(self, string):
  642.         '''Parse a document fragment from a string, returning the
  643.         fragment node.'''
  644.         self._source = string
  645.         parser = self.getParser()
  646.         doctype = self.originalDocument.doctype
  647.         ident = ''
  648.         if doctype:
  649.             if not doctype.internalSubset:
  650.                 pass
  651.             subset = self._getDeclarations()
  652.             if doctype.publicId:
  653.                 ident = 'PUBLIC "%s" "%s"' % (doctype.publicId, doctype.systemId)
  654.             elif doctype.systemId:
  655.                 ident = 'SYSTEM "%s"' % doctype.systemId
  656.             
  657.         else:
  658.             subset = ''
  659.         nsattrs = self._getNSattrs()
  660.         document = _FRAGMENT_BUILDER_TEMPLATE % (ident, subset, nsattrs)
  661.         
  662.         try:
  663.             parser.Parse(document, 1)
  664.         except:
  665.             self.reset()
  666.             raise 
  667.  
  668.         fragment = self.fragment
  669.         self.reset()
  670.         return fragment
  671.  
  672.     
  673.     def _getDeclarations(self):
  674.         """Re-create the internal subset from the DocumentType node.
  675.  
  676.         This is only needed if we don't already have the
  677.         internalSubset as a string.
  678.         """
  679.         doctype = self.context.ownerDocument.doctype
  680.         s = ''
  681.         if doctype:
  682.             for i in range(doctype.notations.length):
  683.                 notation = doctype.notations.item(i)
  684.                 if s:
  685.                     s = s + '\n  '
  686.                 
  687.                 s = '%s<!NOTATION %s' % (s, notation.nodeName)
  688.                 if notation.publicId:
  689.                     s = '%s PUBLIC "%s"\n             "%s">' % (s, notation.publicId, notation.systemId)
  690.                     continue
  691.                 s = '%s SYSTEM "%s">' % (s, notation.systemId)
  692.             
  693.             for i in range(doctype.entities.length):
  694.                 entity = doctype.entities.item(i)
  695.                 if s:
  696.                     s = s + '\n  '
  697.                 
  698.                 s = '%s<!ENTITY %s' % (s, entity.nodeName)
  699.                 if entity.publicId:
  700.                     s = '%s PUBLIC "%s"\n             "%s"' % (s, entity.publicId, entity.systemId)
  701.                 elif entity.systemId:
  702.                     s = '%s SYSTEM "%s"' % (s, entity.systemId)
  703.                 else:
  704.                     s = '%s "%s"' % (s, entity.firstChild.data)
  705.                 if entity.notationName:
  706.                     s = '%s NOTATION %s' % (s, entity.notationName)
  707.                 
  708.                 s = s + '>'
  709.             
  710.         
  711.         return s
  712.  
  713.     
  714.     def _getNSattrs(self):
  715.         return ''
  716.  
  717.     
  718.     def external_entity_ref_handler(self, context, base, systemId, publicId):
  719.         if systemId == _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID:
  720.             old_document = self.document
  721.             old_cur_node = self.curNode
  722.             parser = self._parser.ExternalEntityParserCreate(context)
  723.             self.document = self.originalDocument
  724.             self.fragment = self.document.createDocumentFragment()
  725.             self.curNode = self.fragment
  726.             
  727.             try:
  728.                 parser.Parse(self._source, 1)
  729.             finally:
  730.                 self.curNode = old_cur_node
  731.                 self.document = old_document
  732.                 self._source = None
  733.  
  734.             return -1
  735.         else:
  736.             return ExpatBuilder.external_entity_ref_handler(self, context, base, systemId, publicId)
  737.  
  738.  
  739.  
  740. class Namespaces:
  741.     '''Mix-in class for builders; adds support for namespaces.'''
  742.     
  743.     def _initNamespaces(self):
  744.         self._ns_ordered_prefixes = []
  745.  
  746.     
  747.     def createParser(self):
  748.         '''Create a new namespace-handling parser.'''
  749.         parser = expat.ParserCreate(namespace_separator = ' ')
  750.         parser.namespace_prefixes = True
  751.         return parser
  752.  
  753.     
  754.     def install(self, parser):
  755.         '''Insert the namespace-handlers onto the parser.'''
  756.         ExpatBuilder.install(self, parser)
  757.         if self._options.namespace_declarations:
  758.             parser.StartNamespaceDeclHandler = self.start_namespace_decl_handler
  759.         
  760.  
  761.     
  762.     def start_namespace_decl_handler(self, prefix, uri):
  763.         '''Push this namespace declaration on our storage.'''
  764.         self._ns_ordered_prefixes.append((prefix, uri))
  765.  
  766.     
  767.     def start_element_handler(self, name, attributes):
  768.         if ' ' in name:
  769.             (uri, localname, prefix, qname) = _parse_ns_name(self, name)
  770.         else:
  771.             uri = EMPTY_NAMESPACE
  772.             qname = name
  773.             localname = None
  774.             prefix = EMPTY_PREFIX
  775.         node = minidom.Element(qname, uri, prefix, localname)
  776.         node.ownerDocument = self.document
  777.         _append_child(self.curNode, node)
  778.         self.curNode = node
  779.         if self._ns_ordered_prefixes:
  780.             for prefix, uri in self._ns_ordered_prefixes:
  781.                 if prefix:
  782.                     a = minidom.Attr(_intern(self, 'xmlns:' + prefix), XMLNS_NAMESPACE, prefix, 'xmlns')
  783.                 else:
  784.                     a = minidom.Attr('xmlns', XMLNS_NAMESPACE, 'xmlns', EMPTY_PREFIX)
  785.                 d = a.childNodes[0].__dict__
  786.                 d['data'] = d['nodeValue'] = uri
  787.                 d = a.__dict__
  788.                 d['value'] = d['nodeValue'] = uri
  789.                 d['ownerDocument'] = self.document
  790.                 _set_attribute_node(node, a)
  791.             
  792.             del self._ns_ordered_prefixes[:]
  793.         
  794.         if attributes:
  795.             _attrs = node._attrs
  796.             _attrsNS = node._attrsNS
  797.             for i in range(0, len(attributes), 2):
  798.                 aname = attributes[i]
  799.                 value = attributes[i + 1]
  800.                 if ' ' in aname:
  801.                     (uri, localname, prefix, qname) = _parse_ns_name(self, aname)
  802.                     a = minidom.Attr(qname, uri, localname, prefix)
  803.                     _attrs[qname] = a
  804.                     _attrsNS[(uri, localname)] = a
  805.                 else:
  806.                     a = minidom.Attr(aname, EMPTY_NAMESPACE, aname, EMPTY_PREFIX)
  807.                     _attrs[aname] = a
  808.                     _attrsNS[(EMPTY_NAMESPACE, aname)] = a
  809.                 d = a.childNodes[0].__dict__
  810.                 d['data'] = d['nodeValue'] = value
  811.                 d = a.__dict__
  812.                 d['ownerDocument'] = self.document
  813.                 d['value'] = d['nodeValue'] = value
  814.                 d['ownerElement'] = node
  815.             
  816.         
  817.  
  818.  
  819.  
  820. class ExpatBuilderNS(Namespaces, ExpatBuilder):
  821.     '''Document builder that supports namespaces.'''
  822.     
  823.     def reset(self):
  824.         ExpatBuilder.reset(self)
  825.         self._initNamespaces()
  826.  
  827.  
  828.  
  829. class FragmentBuilderNS(Namespaces, FragmentBuilder):
  830.     '''Fragment builder that supports namespaces.'''
  831.     
  832.     def reset(self):
  833.         FragmentBuilder.reset(self)
  834.         self._initNamespaces()
  835.  
  836.     
  837.     def _getNSattrs(self):
  838.         '''Return string of namespace attributes from this element and
  839.         ancestors.'''
  840.         attrs = ''
  841.         context = self.context
  842.         L = []
  843.         while context:
  844.             if hasattr(context, '_ns_prefix_uri'):
  845.                 for prefix, uri in context._ns_prefix_uri.items():
  846.                     if prefix in L:
  847.                         continue
  848.                     
  849.                     L.append(prefix)
  850.                     if prefix:
  851.                         declname = 'xmlns:' + prefix
  852.                     else:
  853.                         declname = 'xmlns'
  854.                     if attrs:
  855.                         attrs = "%s\n    %s='%s'" % (attrs, declname, uri)
  856.                         continue
  857.                     attrs = " %s='%s'" % (declname, uri)
  858.                 
  859.             
  860.             context = context.parentNode
  861.         return attrs
  862.  
  863.  
  864.  
  865. class ParseEscape(Exception):
  866.     '''Exception raised to short-circuit parsing in InternalSubsetExtractor.'''
  867.     pass
  868.  
  869.  
  870. class InternalSubsetExtractor(ExpatBuilder):
  871.     '''XML processor which can rip out the internal document type subset.'''
  872.     subset = None
  873.     
  874.     def getSubset(self):
  875.         '''Return the internal subset as a string.'''
  876.         return self.subset
  877.  
  878.     
  879.     def parseFile(self, file):
  880.         
  881.         try:
  882.             ExpatBuilder.parseFile(self, file)
  883.         except ParseEscape:
  884.             pass
  885.  
  886.  
  887.     
  888.     def parseString(self, string):
  889.         
  890.         try:
  891.             ExpatBuilder.parseString(self, string)
  892.         except ParseEscape:
  893.             pass
  894.  
  895.  
  896.     
  897.     def install(self, parser):
  898.         parser.StartDoctypeDeclHandler = self.start_doctype_decl_handler
  899.         parser.StartElementHandler = self.start_element_handler
  900.  
  901.     
  902.     def start_doctype_decl_handler(self, name, publicId, systemId, has_internal_subset):
  903.         if has_internal_subset:
  904.             parser = self.getParser()
  905.             self.subset = []
  906.             parser.DefaultHandler = self.subset.append
  907.             parser.EndDoctypeDeclHandler = self.end_doctype_decl_handler
  908.         else:
  909.             raise ParseEscape()
  910.  
  911.     
  912.     def end_doctype_decl_handler(self):
  913.         s = ''.join(self.subset).replace('\r\n', '\n').replace('\r', '\n')
  914.         self.subset = s
  915.         raise ParseEscape()
  916.  
  917.     
  918.     def start_element_handler(self, name, attrs):
  919.         raise ParseEscape()
  920.  
  921.  
  922.  
  923. def parse(file, namespaces = 1):
  924.     """Parse a document, returning the resulting Document node.
  925.  
  926.     'file' may be either a file name or an open file object.
  927.     """
  928.     if namespaces:
  929.         builder = ExpatBuilderNS()
  930.     else:
  931.         builder = ExpatBuilder()
  932.     if isinstance(file, StringTypes):
  933.         fp = open(file, 'rb')
  934.         
  935.         try:
  936.             result = builder.parseFile(fp)
  937.         finally:
  938.             fp.close()
  939.  
  940.     else:
  941.         result = builder.parseFile(file)
  942.     return result
  943.  
  944.  
  945. def parseString(string, namespaces = 1):
  946.     '''Parse a document from a string, returning the resulting
  947.     Document node.
  948.     '''
  949.     if namespaces:
  950.         builder = ExpatBuilderNS()
  951.     else:
  952.         builder = ExpatBuilder()
  953.     return builder.parseString(string)
  954.  
  955.  
  956. def parseFragment(file, context, namespaces = 1):
  957.     """Parse a fragment of a document, given the context from which it
  958.     was originally extracted.  context should be the parent of the
  959.     node(s) which are in the fragment.
  960.  
  961.     'file' may be either a file name or an open file object.
  962.     """
  963.     if namespaces:
  964.         builder = FragmentBuilderNS(context)
  965.     else:
  966.         builder = FragmentBuilder(context)
  967.     if isinstance(file, StringTypes):
  968.         fp = open(file, 'rb')
  969.         
  970.         try:
  971.             result = builder.parseFile(fp)
  972.         finally:
  973.             fp.close()
  974.  
  975.     else:
  976.         result = builder.parseFile(file)
  977.     return result
  978.  
  979.  
  980. def parseFragmentString(string, context, namespaces = 1):
  981.     '''Parse a fragment of a document from a string, given the context
  982.     from which it was originally extracted.  context should be the
  983.     parent of the node(s) which are in the fragment.
  984.     '''
  985.     if namespaces:
  986.         builder = FragmentBuilderNS(context)
  987.     else:
  988.         builder = FragmentBuilder(context)
  989.     return builder.parseString(string)
  990.  
  991.  
  992. def makeBuilder(options):
  993.     '''Create a builder based on an Options object.'''
  994.     if options.namespaces:
  995.         return ExpatBuilderNS(options)
  996.     else:
  997.         return ExpatBuilder(options)
  998.  
  999.